package com.example.onlineanswer.websocket;

import com.alibaba.fastjson.JSON;
import com.example.onlineanswer.common.util.JwtUtil;
import com.example.onlineanswer.mapper.QuestionTypeMapper;
import com.example.onlineanswer.model.dto.QuestionDTO;
import com.example.onlineanswer.model.dto.RankingDTO;
import com.example.onlineanswer.model.entity.Contest;
import com.example.onlineanswer.model.entity.Question;
import com.example.onlineanswer.model.entity.QuestionType;
import com.example.onlineanswer.model.entity.SysUser;
import com.example.onlineanswer.model.vo.UserInfoVO;
import com.example.onlineanswer.service.ContestRankingService;
import com.example.onlineanswer.service.ContestService;
import com.example.onlineanswer.service.QuestionService;
import com.example.onlineanswer.service.UserService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 竞赛WebSocket服务端
 */
@Slf4j
@Component
@ServerEndpoint("/api/ws/contest/{contestId}")
public class ContestWebSocketServer {

    /**
     * 静态变量，用来记录当前在线连接数
     */
    private static AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 线程安全Set，存放每个客户端对应的WebSocket对象
     * 按照竞赛ID分组
     */
    private static Map<Long, CopyOnWriteArrayList<ContestWebSocketServer>> contestWebSocketMap = new ConcurrentHashMap<>();

    /**
     * 存储竞赛当前题目
     */
    private static Map<Long, Question> contestCurrentQuestionMap = new ConcurrentHashMap<>();

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 竞赛ID
     */
    private Long contestId;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 用户昵称
     */
    private String nickname;

    /**
     * 用户头像
     */
    private String avatar;

    /**
     * 用户得分
     */
    private Integer score = 0;

    // 注入服务（静态注入，因为@ServerEndpoint不支持自动注入）
    private static ContestService contestService;
    private static QuestionService questionService;
    private static UserService userService;
    private static ContestRankingService rankingService;
    private static JwtUtil jwtUtil;
    private static QuestionTypeMapper questionTypeMapper;

    @Autowired
    public void setContestService(ContestService contestService) {
        ContestWebSocketServer.contestService = contestService;
    }

    @Autowired
    public void setQuestionService(QuestionService questionService) {
        ContestWebSocketServer.questionService = questionService;
    }

    @Autowired
    public void setUserService(UserService userService) {
        ContestWebSocketServer.userService = userService;
    }
    
    @Autowired
    public void setRankingService(ContestRankingService rankingService) {
        ContestWebSocketServer.rankingService = rankingService;
    }
    
    @Autowired
    public void setJwtUtil(JwtUtil jwtUtil) {
        ContestWebSocketServer.jwtUtil = jwtUtil;
    }
    
    @Autowired
    public void setQuestionTypeMapper(QuestionTypeMapper questionTypeMapper) {
        ContestWebSocketServer.questionTypeMapper = questionTypeMapper;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("contestId") Long contestId) {
        this.session = session;
        this.contestId = contestId;

        // 获取token参数
        String token = session.getRequestParameterMap().get("token").get(0);
        if (token == null || token.isEmpty()) {
            try {
                sendError("未提供有效的身份验证信息");
                session.close();
            } catch (IOException e) {
                log.error("关闭WebSocket连接失败: {}", e.getMessage());
            }
            return;
        }

        try {
            // 处理token，去掉Bearer前缀
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
            }
            
            // 使用JwtUtil从token中获取用户ID
            Long userId = jwtUtil.getUserIdFromToken(token);
            if (userId == null) {
                sendError("无效的身份验证信息");
                session.close();
                return;
            }
            
            // 使用UserService获取用户信息
            UserInfoVO userInfo = userService.getUserInfo(userId);
            if (userInfo == null) {
                sendError("用户不存在");
                session.close();
                return;
            }

            this.userId = userInfo.getId();
            this.nickname = userInfo.getNickname();
            this.avatar = userInfo.getAvatar();

            // 查询竞赛是否存在
            Contest contest = contestService.getById(contestId);
            if (contest == null) {
                sendError("竞赛不存在");
                session.close();
                return;
            }

            // 检查竞赛状态
            if (contest.getStatus() != 1) {
                sendError("竞赛未开始或已结束");
                session.close();
                return;
            }

            // 将WebSocket连接添加到对应竞赛的列表中
            CopyOnWriteArrayList<ContestWebSocketServer> webSocketList = contestWebSocketMap.computeIfAbsent(
                    contestId, k -> new CopyOnWriteArrayList<>());
            webSocketList.add(this);

            // 获取用户排名信息
            RankingDTO userRanking = rankingService.getUserRanking(contestId, userId);
            if (userRanking != null) {
                // 用户已存在排名中，获取分数
                this.score = userRanking.getScore();
            } else {
                // 用户不存在排名中，添加用户
                rankingService.setUserRankingInfo(contestId, userId, nickname, avatar);
                rankingService.updateUserRanking(contestId, userId, 0);
            }

            // 在线人数+1
            addOnlineCount();
            log.info("用户[{}]加入竞赛[{}], 当前在线人数为: {}", userId, contestId, getOnlineCount());

            // 发送当前排名
            broadcastRanking(contestId);

            // 检查是否有当前题目，如果有则发送给新加入的用户
            if (contestCurrentQuestionMap.containsKey(contestId)) {
                Question currentQuestion = contestCurrentQuestionMap.get(contestId);
                sendQuestion(currentQuestion);
            } else {
                // 没有当前题目，可能需要从竞赛中获取当前题目ID
                if (contest.getCurrentQuestionId() != null) {
                    Question currentQuestion = questionService.getById(contest.getCurrentQuestionId());
                    if (currentQuestion != null) {
                        contestCurrentQuestionMap.put(contestId, currentQuestion);
                        sendQuestion(currentQuestion);
                    } else {
                        // 尝试获取竞赛的第一个题目
                        List<Question> questions = questionService.getQuestionsByContestId(contestId);
                        if (questions != null && !questions.isEmpty()) {
                            // 获取排序号为1的题目，如果没有则获取第一个题目
                            Question firstQuestion = questions.stream()
                                    .filter(q -> q.getOrderNum() == 1 || q.getOrderNum() == 0)
                                    .findFirst()
                                    .orElse(questions.get(0));
                                    
                            contestCurrentQuestionMap.put(contestId, firstQuestion);
                            // 更新竞赛当前题目ID
                            contest.setCurrentQuestionId(firstQuestion.getId());
                            contestService.updateById(contest);
                            
                            sendQuestion(firstQuestion);
                            log.info("自动设置竞赛第一个题目 - 竞赛ID: {}, 题目ID: {}", contestId, firstQuestion.getId());
                        }
                    }
                } else {
                    // 尝试获取竞赛的第一个题目
                    List<Question> questions = questionService.getQuestionsByContestId(contestId);
                    if (questions != null && !questions.isEmpty()) {
                        // 获取排序号为1的题目，如果没有则获取第一个题目
                        Question firstQuestion = questions.stream()
                                .filter(q -> q.getOrderNum() == 1 || q.getOrderNum() == 0)
                                .findFirst()
                                .orElse(questions.get(0));
                                
                        contestCurrentQuestionMap.put(contestId, firstQuestion);
                        // 更新竞赛当前题目ID
                        contest.setCurrentQuestionId(firstQuestion.getId());
                        contestService.updateById(contest);
                        
                        sendQuestion(firstQuestion);
                        log.info("自动设置竞赛第一个题目 - 竞赛ID: {}, 题目ID: {}", contestId, firstQuestion.getId());
                    }
                }
            }

        } catch (Exception e) {
            log.error("WebSocket连接异常: {}", e.getMessage());
            try {
                sendError("连接服务器失败");
                session.close();
            } catch (IOException ex) {
                log.error("关闭WebSocket连接失败: {}", ex.getMessage());
            }
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (contestId != null) {
            CopyOnWriteArrayList<ContestWebSocketServer> webSocketList = contestWebSocketMap.get(contestId);
            if (webSocketList != null) {
                webSocketList.remove(this);
                if (webSocketList.isEmpty()) {
                    contestWebSocketMap.remove(contestId);
                }
            }
        }
        
        // 在线人数-1
        subOnlineCount();
        log.info("用户[{}]退出竞赛[{}], 当前在线人数为: {}", userId, contestId, getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来自用户[{}]的消息: {}", userId, message);
        
        try {
            // 解析消息
            WebSocketMessage webSocketMessage = JSON.parseObject(message, WebSocketMessage.class);
            
            // 根据消息类型处理
            switch (webSocketMessage.getType()) {
                case "JOIN":
                    // 已在onOpen中处理加入逻辑
                    break;
                case "SUBMIT_ANSWER":
                    handleSubmitAnswer(webSocketMessage);
                    break;
                case "REQUEST_CURRENT_QUESTION":
                    // 处理请求当前题目
                    handleRequestCurrentQuestion();
                    break;
                case "REQUEST_NEXT_QUESTION":
                    // 处理请求下一题
                    handleRequestNextQuestion(webSocketMessage);
                    break;
                default:
                    log.warn("未知的消息类型: {}", webSocketMessage.getType());
            }
        } catch (Exception e) {
            log.error("处理WebSocket消息异常: {}", e.getMessage());
        }
    }

    /**
     * 处理提交答案消息
     */
    private void handleSubmitAnswer(WebSocketMessage message) {
        try {
            if (message.getQuestionId() == null || message.getAnswer() == null) {
                sendError("提交的答案数据不完整");
                return;
            }

            log.info("处理提交答案 - 用户ID: {}, 题目ID: {}, 答案: {}, 用时: {}",
                    userId, message.getQuestionId(), message.getAnswer(), message.getTimeUsed());

            // 获取当前题目
            Question currentQuestion = contestCurrentQuestionMap.get(contestId);
            
            // 如果当前题目为空，尝试从竞赛中获取当前题目ID
            if (currentQuestion == null) {
                Contest contest = contestService.getById(contestId);
                if (contest != null) {
                    if (contest.getCurrentQuestionId() != null) {
                        currentQuestion = questionService.getById(contest.getCurrentQuestionId());
                        if (currentQuestion != null) {
                            // 更新缓存
                            contestCurrentQuestionMap.put(contestId, currentQuestion);
                            log.info("已从数据库重新加载当前题目 - 题目ID: {}", currentQuestion.getId());
                        }
                    } else {
                        // 尝试获取竞赛的第一个题目
                        List<Question> questions = questionService.getQuestionsByContestId(contestId);
                        if (questions != null && !questions.isEmpty()) {
                            // 获取排序号为1的题目，如果没有则获取第一个题目
                            Question firstQuestion = questions.stream()
                                    .filter(q -> q.getOrderNum() == 1 || q.getOrderNum() == 0)
                                    .findFirst()
                                    .orElse(questions.get(0));
                                    
                            contestCurrentQuestionMap.put(contestId, firstQuestion);
                            // 更新竞赛当前题目ID
                            contest.setCurrentQuestionId(firstQuestion.getId());
                            contestService.updateById(contest);
                            
                            currentQuestion = firstQuestion;
                            log.info("自动设置竞赛第一个题目 - 竞赛ID: {}, 题目ID: {}", contestId, firstQuestion.getId());
                        }
                    }
                }
                
                // 如果仍然为空，但题目ID匹配用户提交的ID，则尝试使用提交的题目ID
                if (currentQuestion == null) {
                    currentQuestion = questionService.getById(message.getQuestionId());
                    if (currentQuestion != null) {
                        log.warn("通过用户提交题目ID加载题目 - 题目ID: {}", currentQuestion.getId());
                        // 更新竞赛当前题目和缓存
                        contestCurrentQuestionMap.put(contestId, currentQuestion);
                        if (contestService != null) {
                            contestService.updateCurrentQuestionId(contestId, currentQuestion.getId());
                        }
                    }
                }
            }

            // 检查提交的题目ID与当前题目ID是否一致
            if (currentQuestion != null && !currentQuestion.getId().equals(message.getQuestionId())) {
                log.error("题目ID不匹配 - 当前题目ID: {}, 提交题目ID: {}, 用户ID: {}", 
                          currentQuestion.getId(), message.getQuestionId(), userId);
                
                // 如果不匹配，检查提交的题目是否合法
                Question submittedQuestion = questionService.getById(message.getQuestionId());
                if (submittedQuestion != null) {
                    // 检查提交的题目是否属于当前竞赛
                    List<Question> contestQuestions = questionService.getQuestionsByContestId(contestId);
                    boolean isValidQuestion = contestQuestions.stream()
                            .anyMatch(q -> q.getId().equals(message.getQuestionId()));
                    
                    if (isValidQuestion) {
                        log.warn("用户提交的题目与当前题目不同，但题目有效，继续处理 - 用户ID: {}, 提交题目ID: {}", 
                                userId, message.getQuestionId());
                        currentQuestion = submittedQuestion;
                        
                        // 更新当前题目缓存
                        contestCurrentQuestionMap.put(contestId, currentQuestion);
                    } else {
                        sendError("提交的题目不属于当前竞赛，请刷新页面重试");
                        return;
                    }
                } else {
                    sendError("提交的题目与当前题目不匹配，请刷新页面重试");
                    return;
                }
            }
            
            if (currentQuestion == null) {
                log.error("找不到当前题目信息 - 竞赛ID: {}, 提交题目ID: {}", contestId, message.getQuestionId());
                sendError("当前题目信息不存在，请刷新页面重试");
                return;
            }

            // 校验答案
            boolean isCorrect = questionService.checkAnswer(currentQuestion.getId(), message.getAnswer());
            log.info("答案校验结果 - 用户ID: {}, 题目ID: {}, 答案: {}, 是否正确: {}",
                    userId, message.getQuestionId(), message.getAnswer(), isCorrect);
            
            // 记录用户答题情况到数据库（可以使用异步方式）
            try {
                saveUserAnswer(contestId, userId, currentQuestion.getId(), message.getAnswer(), isCorrect, message.getTimeUsed());
            } catch (Exception e) {
                log.error("记录用户答题情况失败: {}", e.getMessage(), e);
                // 不中断主流程，继续执行
            }
            
            // 构建答题结果
            WebSocketMessage resultMessage = new WebSocketMessage();
            resultMessage.setType("ANSWER_RESULT");
            
            AnswerResultData resultData = new AnswerResultData();
            resultData.setCorrect(isCorrect);
            
            if (isCorrect) {
                // 计算得分 (可以根据难度和用时计算)
                int questionScore = currentQuestion.getScore() != null ? currentQuestion.getScore() : 0;
                int timeUsed = message.getTimeUsed() != null ? message.getTimeUsed() : 0;
                int timeLimit = currentQuestion.getTimeLimit() != null ? currentQuestion.getTimeLimit() : 60;
                
                // 得分计算逻辑：基础分 * (1 - 用时/总时间 * 0.5)，确保至少能得到50%的分数
                double timeRatio = timeLimit > 0 ? Math.min(1.0, (double) timeUsed / timeLimit) : 0;
                int earnedScore = (int) Math.round(questionScore * (1 - timeRatio * 0.5));
                
                // 确保至少有一分
                if (earnedScore <= 0) {
                    earnedScore = 1;
                }
                
                this.score += earnedScore;
                resultData.setScore(earnedScore);
                
                log.info("答对加分 - 用户ID: {}, 题目ID: {}, 得分: {}, 总分: {}",
                        userId, message.getQuestionId(), earnedScore, this.score);
                
                // 更新用户排名（使用Redis）
                if (rankingService != null) {
                    try {
                        rankingService.updateUserRanking(contestId, userId, this.score);
                        // 广播排名更新
                        broadcastRanking(contestId);
                    } catch (Exception e) {
                        log.error("更新排名失败: {}", e.getMessage(), e);
                    }
                } else {
                    log.warn("排名服务不可用，无法更新用户排名");
                }
                
                // 进入下一题逻辑 - 答对才能进入下一题
                try {
                    // 先获取竞赛全部题目数量，以确定是否有下一题
                    List<Question> allQuestions = questionService.getQuestionsByContestId(contestId);
                    int totalQuestions = allQuestions != null ? allQuestions.size() : 0;
                    log.info("竞赛总题目数量: {}", totalQuestions);
                    
                    // 获取当前题目在全部题目中的位置
                    int currentIndex = -1;
                    if (allQuestions != null) {
                        for (int i = 0; i < allQuestions.size(); i++) {
                            if (allQuestions.get(i).getId().equals(currentQuestion.getId())) {
                                currentIndex = i;
                                break;
                            }
                        }
                    }
                    log.info("当前题目索引: {}, 总题目数: {}", currentIndex, totalQuestions);
                    
                    Question nextQuestion = questionService.getNextQuestion(contestId, currentQuestion.getId());
                    if (nextQuestion != null) {
                        log.info("答对后切换到下一题 - 竞赛ID: {}, 当前题目ID: {}, 下一题ID: {}, 答对用户: {}",
                                contestId, currentQuestion.getId(), nextQuestion.getId(), userId);
                        
                        // 更新当前题目
                        contestCurrentQuestionMap.put(contestId, nextQuestion);
                        
                        // 更新竞赛当前题目ID
                        if (contestService != null) {
                            contestService.updateCurrentQuestionId(contestId, nextQuestion.getId());
                        }
                        
                        // 广播新题目，所有参赛者同时接收到新题目，剩余时间从满值开始
                        QuestionDTO nextQuestionDTO = questionService.getQuestionDetails(nextQuestion.getId());
                        // 发送题目时不指定剩余时间，表示从满时间开始计时
                        broadcastQuestion(contestId, nextQuestion);
                    } else {
                        // 如果通过正常查询没找到下一题，再次检查是否真的是最后一题
                        if (currentIndex >= 0 && currentIndex >= totalQuestions - 1) {
                            log.info("已经是最后一题，竞赛结束 - 竞赛ID: {}, 当前题目索引: {}, 总题目数: {}", 
                                    contestId, currentIndex, totalQuestions);
                            // 确认是最后一题，竞赛结束
                            broadcastContestEnd(contestId);
                            
                            // 更新竞赛状态为已结束
                            if (contestService != null) {
                                contestService.endContest(contestId);
                            }
                        } else if (currentIndex >= 0 && currentIndex < totalQuestions - 1 && allQuestions != null) {
                            // 如果不是最后一题，但getNextQuestion返回null，尝试直接获取下一个题目
                            Question forcedNextQuestion = allQuestions.get(currentIndex + 1);
                            log.warn("getNextQuestion返回null但不是最后一题，强制获取下一题 - ID: {}", 
                                    forcedNextQuestion.getId());
                            
                            // 更新当前题目
                            contestCurrentQuestionMap.put(contestId, forcedNextQuestion);
                            
                            // 更新竞赛当前题目ID
                            if (contestService != null) {
                                contestService.updateCurrentQuestionId(contestId, forcedNextQuestion.getId());
                            }
                            
                            // 广播新题目
                            broadcastQuestion(contestId, forcedNextQuestion);
                        } else {
                            log.warn("找不到下一题，但题目索引检查异常 - 当前索引: {}, 总题目数: {}", 
                                    currentIndex, totalQuestions);
                            // 异常情况，通知管理员
                            sendError("题目顺序异常，请联系管理员");
                        }
                    }
                } catch (Exception e) {
                    log.error("切换题目失败: {}", e.getMessage(), e);
                }
            } else {
                resultData.setMessage("回答错误，请继续努力！");
                log.info("答案错误 - 用户ID: {}, 题目ID: {}", userId, message.getQuestionId());
            }
            
            resultMessage.setData(resultData);
            
            // 发送答题结果给用户
            String resultJson = JSON.toJSONString(resultMessage);
            log.debug("发送答题结果: {}", resultJson);
            sendMessage(resultJson);
        } catch (Exception e) {
            log.error("处理答案提交异常: {}", e.getMessage(), e);
            sendError("处理答案时发生错误: " + e.getMessage());
        }
    }

    /**
     * 保存用户答题记录（可以根据实际情况实现）
     */
    private void saveUserAnswer(Long contestId, Long userId, Long questionId, String answer, boolean isCorrect, Integer timeUsed) {
        // 这里可以调用Service层的方法保存答题记录到数据库
        // 例如：answerRecordService.saveAnswerRecord(contestId, userId, questionId, answer, isCorrect, timeUsed);
        
        // 简单记录日志，实际实现时可以替换为数据库操作
        log.info("记录答题 - 竞赛ID: {}, 用户ID: {}, 题目ID: {}, 答案: {}, 是否正确: {}, 用时: {}秒",
                 contestId, userId, questionId, answer, isCorrect, timeUsed);
    }

    /**
     * 广播排名信息给所有参与竞赛的用户
     */
    private void broadcastRanking(Long contestId) {
        // 从Redis获取排名数据（获取前20名）
        List<RankingDTO> rankings = rankingService.getRankingList(contestId, 0, 19);
        if (rankings == null || rankings.isEmpty()) return;
        
        WebSocketMessage message = new WebSocketMessage();
        message.setType("RANKING");
        message.setData(rankings);
        
        broadcast(contestId, JSON.toJSONString(message));
    }

    /**
     * 广播新题目给所有参与竞赛的用户
     */
    private void broadcastQuestion(Long contestId, Question question) {
        WebSocketMessage message = new WebSocketMessage();
        message.setType("QUESTION");
        
        // 转换为DTO，包含选项等信息
        QuestionDTO questionDTO = questionService.getQuestionDetails(question.getId());
        message.setData(questionDTO);
        
        broadcast(contestId, JSON.toJSONString(message));
    }

    /**
     * 广播竞赛结束消息
     */
    private void broadcastContestEnd(Long contestId) {
        WebSocketMessage message = new WebSocketMessage();
        message.setType("CONTEST_END");
        
        broadcast(contestId, JSON.toJSONString(message));
    }

    /**
     * 发送题目给指定用户
     */
    private void sendQuestion(Question question) {
        WebSocketMessage message = new WebSocketMessage();
        message.setType("QUESTION");
        
        // 转换为DTO，包含选项等信息
        QuestionDTO questionDTO = questionService.getQuestionDetails(question.getId());
        if (questionDTO == null) {
            sendError("获取题目信息失败");
            return;
        }
        
        // 确保所有需要的字段都已设置
        if (questionDTO.getTypeName() == null && questionDTO.getTypeId() != null) {
            // 根据类型ID获取类型名称
            QuestionType questionType = questionTypeMapper.selectById(questionDTO.getTypeId());
            if (questionType != null) {
                questionDTO.setTypeName(questionType.getTypeName());
            }
        }
        
        message.setData(questionDTO);
        sendMessage(JSON.toJSONString(message));
    }

    /**
     * 发送错误消息
     */
    private void sendError(String errorMessage) {
        log.warn("发送错误消息给用户[{}]: {}", userId, errorMessage);
        
        try {
            WebSocketMessage message = new WebSocketMessage();
            message.setType("ERROR");
            message.setData(errorMessage);
            
            String jsonMessage = JSON.toJSONString(message);
            log.debug("错误消息内容: {}", jsonMessage);
            
            if (this.session != null && this.session.isOpen()) {
                this.session.getBasicRemote().sendText(jsonMessage);
            } else {
                log.error("无法发送错误消息: WebSocket会话已关闭或为null");
            }
        } catch (Exception e) {
            log.error("发送错误消息异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 广播消息到指定竞赛的所有用户
     */
    private void broadcast(Long contestId, String message) {
        CopyOnWriteArrayList<ContestWebSocketServer> webSocketList = contestWebSocketMap.get(contestId);
        if (webSocketList != null && !webSocketList.isEmpty()) {
            for (ContestWebSocketServer item : webSocketList) {
                item.sendMessage(message);
            }
        }
    }

    /**
     * 发送消息给指定会话
     */
    public void sendMessage(String message) {
        if (this.session == null) {
            log.error("无法发送消息: WebSocket会话为null, 用户ID: {}", userId);
            return;
        }
        
        if (!this.session.isOpen()) {
            log.error("无法发送消息: WebSocket会话已关闭, 用户ID: {}", userId);
            return;
        }
        
        try {
            log.debug("发送消息给用户 {}: {}", userId, message);
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送WebSocket消息IO异常: {}, 用户ID: {}", e.getMessage(), userId, e);
        } catch (Exception e) {
            log.error("发送WebSocket消息未知异常: {}, 用户ID: {}", e.getMessage(), userId, e);
        }
    }

    /**
     * 处理WebSocket错误
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket发生错误: {}, 会话ID: {}", error.getMessage(), session.getId());
    }

    /**
     * 获取当前在线人数
     */
    public static int getOnlineCount() {
        return onlineCount.get();
    }

    /**
     * 当前在线人数加1
     */
    public static void addOnlineCount() {
        onlineCount.incrementAndGet();
    }

    /**
     * 当前在线人数减1
     */
    public static void subOnlineCount() {
        onlineCount.decrementAndGet();
    }

    /**
     * WebSocket消息
     */
    @Data
    public static class WebSocketMessage {
        /**
         * 消息类型
         */
        private String type;
        
        /**
         * 竞赛ID
         */
        private Long contestId;
        
        /**
         * 题目ID（用于提交答案）
         */
        private Long questionId;
        
        /**
         * 下一题ID（用于REQUEST_NEXT_QUESTION）
         */
        private Long nextQuestionId;
        
        /**
         * 答案（用于提交答案）
         */
        private String answer;
        
        /**
         * 用时（秒）
         */
        private Integer timeUsed;
        
        /**
         * 消息数据
         */
        private Object data;
    }

    /**
     * 答题结果数据
     */
    @Data
    public static class AnswerResultData {
        /**
         * 是否回答正确
         */
        private boolean correct;
        
        /**
         * 获得的分数
         */
        private Integer score;
        
        /**
         * 提示消息
         */
        private String message;
    }

    /**
     * 处理请求当前题目
     */
    private void handleRequestCurrentQuestion() {
        // 获取当前竞赛信息
        Contest contest = contestService.getById(this.contestId);
        if (contest == null) {
            sendError("当前竞赛信息不存在");
            return;
        }
        
        // 如果竞赛存在但没有设置当前题目，尝试获取第一个题目
        if (contest.getCurrentQuestionId() == null) {
            try {
                // 获取竞赛中的第一个题目
                List<Question> questions = questionService.getQuestionsByContestId(this.contestId);
                if (questions == null || questions.isEmpty()) {
                    sendError("当前竞赛没有题目");
                    return;
                }
                
                // 获取排序号为1的题目，如果没有则获取第一个题目
                Question firstQuestion = questions.stream()
                        .filter(q -> q.getOrderNum() == 1 || q.getOrderNum() == 0)
                        .findFirst()
                        .orElse(questions.get(0));
                
                // 设置为当前题目
                contest.setCurrentQuestionId(firstQuestion.getId());
                boolean updateResult = contestService.updateById(contest);
                
                if (updateResult) {
                    // 更新缓存
                    contestCurrentQuestionMap.put(contestId, firstQuestion);
                    log.info("设置并更新第一个题目成功 - 竞赛ID: {}, 题目ID: {}", contestId, firstQuestion.getId());
                    
                    // 发送题目给用户
                    sendQuestion(firstQuestion);
                } else {
                    log.error("更新竞赛第一个题目失败 - 竞赛ID: {}", contestId);
                    sendError("设置当前题目失败，请稍后重试");
                }
                return;
            } catch (Exception e) {
                log.error("获取第一个题目失败: {}", e.getMessage(), e);
                sendError("获取题目失败，请稍后重试");
                return;
            }
        }
        
        // 获取当前题目
        Question currentQuestion = questionService.getById(contest.getCurrentQuestionId());
        if (currentQuestion == null) {
            log.error("当前题目不存在 - 竞赛ID: {}, 题目ID: {}", contestId, contest.getCurrentQuestionId());
            sendError("获取当前题目失败");
            return;
        }
        
        // 更新缓存
        contestCurrentQuestionMap.put(contestId, currentQuestion);
        log.info("获取当前题目成功 - 竞赛ID: {}, 题目ID: {}", contestId, currentQuestion.getId());
        
        // 发送题目给用户
        sendQuestion(currentQuestion);
    }

    /**
     * 处理请求下一题
     */
    private void handleRequestNextQuestion(WebSocketMessage message) {
        // 检查是否为管理员
        if (userId == null) {
            sendError("身份验证失败");
            return;
        }
        
        // 只有管理员才能手动切换题目
        UserInfoVO adminUser = userService.getUserInfo(userId);
        if (adminUser == null || adminUser.getRoleCode() == null || 
            !(adminUser.getRoleCode().equals("ADMIN") || adminUser.getRoleCode().equals("TEACHER"))) {
            log.warn("非管理员用户尝试切换题目 - 用户ID: {}, 竞赛ID: {}", userId, contestId);
            sendError("您没有权限请求切换题目");
            return;
        }
        
        log.info("管理员请求切换下一题 - 用户ID: {}, 管理员: {}, 竞赛ID: {}", 
                userId, adminUser.getNickname(), contestId);
        
        try {
            // 获取当前题目
            Question currentQuestion = contestCurrentQuestionMap.get(contestId);
            Long currentQuestionId = null;
            
            // 如果当前题目为空，尝试从竞赛中获取
            if (currentQuestion == null) {
                Contest contest = contestService.getById(contestId);
                if (contest == null) {
                    sendError("当前竞赛不存在");
                    return;
                }
                
                currentQuestionId = contest.getCurrentQuestionId();
                if (currentQuestionId != null) {
                    currentQuestion = questionService.getById(currentQuestionId);
                    if (currentQuestion != null) {
                        // 更新缓存
                        contestCurrentQuestionMap.put(contestId, currentQuestion);
                        log.info("从数据库更新当前题目缓存 - 竞赛ID: {}, 题目ID: {}", contestId, currentQuestion.getId());
                    }
                }
            } else {
                currentQuestionId = currentQuestion.getId();
            }
            
            // 获取下一题
            Long nextQuestionId = null;
            if (message.getQuestionId() != null) {
                // 指定了下一题ID
                nextQuestionId = message.getQuestionId();
                log.info("管理员指定下一题ID: {}", nextQuestionId);
            } else {
                // 自动获取下一题
                if (currentQuestionId != null) {
                    Question nextQuestion = questionService.getNextQuestion(contestId, currentQuestionId);
                    if (nextQuestion != null) {
                        nextQuestionId = nextQuestion.getId();
                        log.info("自动获取下一题ID: {}", nextQuestionId);
                    } else {
                        log.info("没有找到下一题 - 竞赛ID: {}, 当前题目ID: {}", contestId, currentQuestionId);
                    }
                } else {
                    // 如果没有当前题目，尝试获取第一个题目
                    List<Question> questions = questionService.getQuestionsByContestId(contestId);
                    if (questions != null && !questions.isEmpty()) {
                        // 获取第一个题目
                        Question firstQuestion = questions.stream()
                                .filter(q -> q.getOrderNum() == 1 || q.getOrderNum() == 0)
                                .findFirst()
                                .orElse(questions.get(0));
                        
                        nextQuestionId = firstQuestion.getId();
                        log.info("没有当前题目，使用第一个题目 - 竞赛ID: {}, 第一题ID: {}", 
                                contestId, nextQuestionId);
                    }
                }
            }
            
            if (nextQuestionId != null) {
                try {
                    Question nextQuestion = questionService.getById(nextQuestionId);
                    if (nextQuestion != null) {
                        log.info("手动请求切换到下一题 - 竞赛ID: {}, 当前题目ID: {}, 下一题ID: {}, 请求用户: {}",
                                contestId, currentQuestionId, nextQuestionId, userId);
                        
                        // 更新当前题目缓存
                        contestCurrentQuestionMap.put(contestId, nextQuestion);
                        
                        // 更新竞赛当前题目ID
                        if (contestService != null) {
                            boolean updateResult = contestService.updateCurrentQuestionId(contestId, nextQuestion.getId());
                            if (!updateResult) {
                                log.error("更新竞赛当前题目ID失败 - 竞赛ID: {}, 题目ID: {}", contestId, nextQuestion.getId());
                                sendError("更新竞赛当前题目失败，但已广播新题目");
                            }
                        }
                        
                        // 广播新题目，所有参赛者同时接收到新题目
                        broadcastQuestion(contestId, nextQuestion);
                    } else {
                        log.error("指定的下一题不存在 - 竞赛ID: {}, 题目ID: {}", contestId, nextQuestionId);
                        sendError("指定的下一题不存在");
                    }
                } catch (Exception e) {
                    log.error("切换到下一题失败: {}", e.getMessage(), e);
                    sendError("切换到下一题失败: " + e.getMessage());
                }
            } else {
                log.warn("没有找到下一题 - 竞赛ID: {}, 当前题目ID: {}", contestId, currentQuestionId);
                sendError("没有找到下一题");
            }
        } catch (Exception e) {
            log.error("处理请求下一题异常: {}", e.getMessage(), e);
            sendError("处理请求失败: " + e.getMessage());
        }
    }
} 